/**
 * 
 */
package jnzb.control;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.util.Properties;

import jnzb.nntp.NewsAccount;

/**
 * Represents the apps config, which is in an xml file
 * 
 * @author Rid
 * 
 */
public class Configuration {

	public static final String SEGMENT_FOLDER = "segments";
	// public static final String PARTS_FOLDER = "parts";
	public static final String NZB_FOLDER = "nzb";
	private static final Configuration INSTANCE = new Configuration();

	private static final String CONFIG_FILENAME = "jnzb.properties";

	// Property keys
	private static final String PROPS_HOST = "jnzb.usenet.host";
	private static final String PROPS_PORT = "jnzb.usenet.port";
	private static final String PROPS_USERNAME = "jnzb.usenet.username";
	private static final String PROPS_PASSWORD = "jnzb.usenet.password";
	private static final String PROPS_SECURE = "jnzb.usenet.isSecure";

	private static final String PROPS_ROOT_DIRECTORY = "jnzb.storage.directory";
	private static final String PROPS_PAR2_COMMAND = "jnzb.par2.autoLaunchCommand";
	private static final String PROPS_AUTODOWNLOAD_DIRECTORY = "jnzb.download.autoDownloadDirectory";
	private static final String PROPS_AGENT_PORT = "jnzb.agent.port";
	private static final String PROPS_LOGFILENAME = "jnzb.log.filename";
	private static final String PROPS_LOG_LEVEL = "jnzb.log.level";
	private static final String PROPS_CONNECTION_ATTEMPTS = "jnzb.usenet.connectionAttempts";
	private static final String PROPS_IGNORE_SAMPLES = "jnzb.download.ignoreSampleFiles";
	private static final String PROPS_IGNORE_PARS = "jnzb.download.ignoreParFiles";
	private static final String PROPS_AUTOLAUNCH_PAR = "jnzb.download.autolaunchPar2";
	private static final String PROPS_DOWNLOAD_RETRY = "jnzb.download.retryPeriod";
	private static final String PROPS_JNZB_HOME = "JNZB_HOME";
	private static final String PROPS_ALWAYS_CONTINUE = "jnzb.continueDownload.ask";

	private static final String RMI_START = "rmi://localhost:";
	private static final String RMI_END = "/jnzbRemoteQueue";

	private Properties props = new Properties();
	private NewsAccount newsAccount = null;

	/**
	 * Indicates if the config file is present
	 * 
	 * @return
	 */
	public static boolean configPresent() {
		return new File(getJNZBHome() + CONFIG_FILENAME).exists();
	}

	private Configuration() {
		try {
			// use jnzb home if defined
			props.load(new FileReader(getJNZBHome() + CONFIG_FILENAME));
		} catch (FileNotFoundException e) {
			props.clear();
			System.err.println("Could not find the properties file - "
					+ CONFIG_FILENAME);
		} catch (IOException e) {
			props.clear();
			System.err.println("Error reading properties file - "
					+ CONFIG_FILENAME);
		}
	}

	/**
	 * Returns the instance of the configuration
	 * 
	 * @return
	 */
	public static Configuration getInstance() {
		return INSTANCE;
	}

	/**
	 * Returns the news account configured
	 * 
	 * @return
	 */
	public NewsAccount getAccount() {
		if (newsAccount == null) {
			newsAccount = new NewsAccount();
			newsAccount.setHost(props.getProperty(PROPS_HOST));
			newsAccount
					.setPort(Integer.parseInt(props.getProperty(PROPS_PORT)));
			newsAccount.setUsername(props.getProperty(PROPS_USERNAME));
			newsAccount.setPassword(props.getProperty(PROPS_PASSWORD));
			newsAccount.setSecure(Boolean.parseBoolean(props
					.getProperty(PROPS_SECURE)));
		}
		return newsAccount;
	}

	/**
	 * This is temp
	 * 
	 * @return The root loction for all file processing. Must end with a /
	 */
	public String getRoot() {
		return props.getProperty(PROPS_ROOT_DIRECTORY);
	}

	/**
	 * Create the path for segments
	 * 
	 * @param nzbFilename
	 *            - this is used as a sub-folder
	 * @return
	 */
	public String getSegmentPath(String nzbFilename) {
		return getRoot() + getNZBWorkFoldername(nzbFilename) + "/"
				+ SEGMENT_FOLDER + "/";
	}

	/**
	 * Create the path for parts - stored in the root
	 * 
	 * @param nzbFilename
	 *            - this is used as a sub-folder
	 * @return
	 */
	public String getPartsPath(String nzbFilename) {
		return getRoot() + getNZBWorkFoldername(nzbFilename) + "/";
	}

	/**
	 * Create the path for parts
	 * 
	 * @param nzbFilename
	 *            - this is used as a sub-folder
	 * @return
	 */
	public String getNZBPath(String nzbFilename) {
		return getRoot() + getNZBWorkFoldername(nzbFilename) + "/" + NZB_FOLDER
				+ "/";
	}

	public String getNZBWorkFoldername(String filename) {
		if (filename.endsWith(".nzb")) {
			filename = filename.substring(0, filename.indexOf(".nzb"));
		}
		return filename;
	}

	/**
	 * Get the directory to monitor for dropped NZB files
	 * 
	 * @return
	 */
	public String getAutoDownloadDirectory() {
		return props.getProperty(PROPS_AUTODOWNLOAD_DIRECTORY);
	}

	/**
	 * Get the name of the logfile
	 * 
	 * @return
	 */
	public String getLogfilename() {
		if (isJNZBDefined()) {
			return getJNZBHome() + props.getProperty(PROPS_LOGFILENAME);
		}
		return props.getProperty(PROPS_LOGFILENAME);
	}

	/**
	 * Returns the number of connection attempts to make
	 * 
	 * @return
	 */
	public int getConnectionAttempts() {
		try {
			return Integer.parseInt(props
					.getProperty(PROPS_CONNECTION_ATTEMPTS));
		} catch (NumberFormatException e) {
			return 0;
		}
	}

	/**
	 * Indicates if the queueing agent is enabled
	 * 
	 * @return
	 */
	public boolean agentEnabled() {
		String agentPort = props.getProperty(PROPS_AGENT_PORT);
		return agentPort != null && agentPort.trim().length() > 0;
	}

	/**
	 * Indicates if the queueing agent is enabled
	 * 
	 * @return
	 */
	public int getAgentPort() {
		try {
			return Integer.parseInt(props.getProperty(PROPS_AGENT_PORT));
		} catch (NumberFormatException e) {
			return 0;
		}
	}

	/**
	 * Gets the location of the JNZB remote queueing object.
	 * 
	 * @return
	 */
	public String getRemoteLocation() {
		String agentPort = props.getProperty(PROPS_AGENT_PORT);
		return RMI_START + agentPort + RMI_END;
	}

	/**
	 * Indicates if we should ignore sample files
	 * 
	 * @return
	 */
	public boolean ignoreSampleFiles() {
		return Boolean.parseBoolean(props.getProperty(PROPS_IGNORE_SAMPLES));
	}

	/**
	 * Indicates if we should ignore PAR block files
	 * 
	 * @return
	 */
	public boolean ignoreParFiles() {
		return Boolean.parseBoolean(props.getProperty(PROPS_IGNORE_PARS));
	}

	/**
	 * Indicates if we should auto launch PAR files once downloaded
	 * 
	 * @return
	 */
	public boolean autoLaunchPar() {
		return Boolean.parseBoolean(props.getProperty(PROPS_AUTOLAUNCH_PAR));
	}

	/**
	 * Returns the value of JNZB_HOME if defined as a system property. Note, if
	 * defined, will always return with a / at the end
	 * 
	 * @return JNZB_HOME or empty string if not
	 */
	public static String getJNZBHome() {
		String jnzbHome = System.getProperty(PROPS_JNZB_HOME);
		if (jnzbHome != null && jnzbHome.trim().length() > 0) {
			if (!jnzbHome.trim().endsWith("/")) {
				return jnzbHome + "/";
			}
			return jnzbHome;
		}
		return "";
	}

	/**
	 * Checks if the system property for the home location of JNZB is defined
	 * 
	 * @return
	 */
	public static boolean isJNZBDefined() {
		String jnzbHome = System.getProperty(PROPS_JNZB_HOME);
		return jnzbHome != null && jnzbHome.trim().length() > 0;
	}

	/**
	 * Returns the log level defined in the log file.
	 * 
	 * @return Log level value or -1 if not defined
	 */
	public int getLogLevel() {
		try {
			return Integer.parseInt(props.getProperty(PROPS_LOG_LEVEL));
		} catch (NumberFormatException e) {
			return -1;
		}
	}

	/**
	 * Returns the amount in seconds to wait between automatically trying to
	 * start downloading after an error
	 * 
	 * @return retry value in seconds or -1 if not defined
	 */
	public int getAutoRetryValue() {
		try {
			return Integer.parseInt(props.getProperty(PROPS_LOG_LEVEL));
		} catch (NumberFormatException e) {
			return -1;
		}
	}

	public boolean getAlwaysContinue() {
		return Boolean.parseBoolean(props.getProperty(PROPS_ALWAYS_CONTINUE));
	}
}
